#include "CUpAppendTable.h"
#include "CTableConfigure.h"
#include "CLogRecord.h"
#include "CppSQLite3.h"
#include "CUKeyUValueCalc.h"
#include <sstream>
#include <iostream>
#include <algorithm>

void CUpAppendTable::setTableConfigure(const CTableConfigurePtr& tableConfigure)
{
	CTableBase::setTableConfigure(tableConfigure);
}

int CUpAppendTable::InitTable()
{
	m_tableConfigure->setTableField(CTableField("uKey", EFieldType::EFieldTypeInt, 0));
	m_tableConfigure->setTableField(CTableField("uValue", EFieldType::EFieldTypeInt, 0));

	int nRet = CTableBase::InitTable();

	return nRet;
}

int CUpAppendTable::beforeWriteRecord(CLogRecordPtr logRecord)
{
	// Call base class to handle common fields including UUID
	CTableBase::beforeWriteRecord(logRecord);
	
	CUKeyUValueCalc calc(this);
	calc.CalculateUKeyUValue(logRecord);

	if (!logRecord->hasField("uKey"))
		logRecord->AddField("uKey", (uint64_t)calc.getUKey());
	
	if (!logRecord->hasField("uValue"))
		logRecord->AddField("uValue", (uint64_t)calc.getUValue());

	return 0;
}

int CUpAppendTable::writeRecord(CLogRecordPtr logRecord)
{
	try {
		// Check if we have the required components
		if (!logRecord || !m_tableConfigure || !m_logDatabase) {
			return -1; // Error: missing record, configuration, or database
		}
		
		// Get the database connection
		CppSQLite3DB* db = m_logDatabase->getDatabaseConnection();
		if (!db) {
			return -2; // Error: no database connection
		}
		
		// Get the table name
		std::string tableName = m_tableConfigure->getTableName();
		if (tableName.empty()) {
			return -3; // Error: no table name
		}
		
		// Get uKey and uValue from the record
		auto& recordFields = logRecord->GetFields();
		uint64_t uKey = 0;
		uint64_t uValue = 0;
		
		auto uKeyIt = recordFields.find("uKey");
		if (uKeyIt != recordFields.end()) {
			const CLogValue& uKeyValue = uKeyIt->second->GetValue();
			if (uKeyValue.type() == typeid(uint64_t)) {
				uKey = boost::get<uint64_t>(uKeyValue);
			}
		}
		
		auto uValueIt = recordFields.find("uValue");
		if (uValueIt != recordFields.end()) {
			const CLogValue& uValueValue = uValueIt->second->GetValue();
			if (uValueValue.type() == typeid(uint64_t)) {
				uValue = boost::get<uint64_t>(uValueValue);
			}
		}
		
		// Check if record with same uKey exists
		std::stringstream checkSql;
		checkSql << "SELECT uValue, uuid FROM " << tableName << " WHERE uKey = " << uKey;
		
		CppSQLite3Query query = db->execQuery(checkSql.str().c_str());
		
		if (!query.eof()) {
			// Record with same uKey exists
			uint64_t existingUValue = query.getInt64Field("uValue");
			std::string existingUuid = query.getStringField("uuid");
			
			if (existingUValue == uValue) {
				// uValue is the same, no need to insert
				std::cout << "Record with uKey " << uKey << " and uValue " << uValue << " already exists, skipping insertion" << std::endl;
				query.finalize();
				return 0; // Success - no action needed
			} else {
				// uValue is different, update the record's uuid and delete old record
				std::cout << "Found existing record with uKey " << uKey << " and uValue " << existingUValue << ", updating uuid and deleting old record" << std::endl;
				
				if(existingUuid.empty())
					existingUuid = generateUUID();

				logRecord->AddField("uuid", existingUuid);
				
				// Delete the old record
				std::stringstream deleteSql;
				deleteSql << "DELETE FROM " << tableName << " WHERE uKey = " << uKey;
				db->execDML(deleteSql.str().c_str());
			}
		}
		
		query.finalize();
		
		// Insert the record (either new or updated)
		return InsertRecord(logRecord);
		
	} catch (const CppSQLite3Exception& e) {
		// Handle SQLite exceptions
		//std::cout << "SQLite error in writeRecord: " << e.errorMessage() << std::endl;
		return -4; // Error: SQLite exception
	} catch (const std::exception& e) {
		// Handle other exceptions
		std::cout << "General error in writeRecord: " << e.what() << std::endl;
		return -5; // Error: general exception
	}
}

int CUpAppendTable::getTableType() const
{
	return TableTypeUpAppend;
}



